package org.bdware.doip.core.crypto;

import com.nimbusds.jose.jwk.JWK;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.ssl.SslHandler;
import org.apache.log4j.Logger;
import org.bdware.doip.core.codec.packet.PacketMessageCodec;
import org.bdware.doip.core.codec.packet.PacketMessageCodecImpl;
import org.bdware.doip.core.doipMessage.DoipMessage;
import org.bdware.doip.core.doipMessage.MessageCredential;
import org.bdware.doip.core.utils.GlobalConfigurations;
import org.bdware.irp.client.GlobalIrpClient;
import org.bdware.irp.crypto.CertUtils;
import org.bdware.irp.exception.IrpClientException;
import org.bdware.irp.stateinfo.UserStateInfo;

import javax.net.ssl.SSLSession;
import javax.security.cert.X509Certificate;

public class CryptoUtils {

    static Logger logger = Logger.getLogger(CryptoUtils.class);

    /**
     *
     * @param ctx tls connection
     * @return null if not a valid tls connection
     */
    public static String getUserIDByContext(ChannelHandlerContext ctx){
        try {
            SSLSession ss =  ctx.pipeline().get(SslHandler.class).engine().getSession();
            X509Certificate cert;
            cert = ss.getPeerCertificateChain()[0];
            return cert.getSubjectDN().getName();
        } catch (Exception e) {
//            e.printStackTrace();
            logger.debug("unable to get client ID from Context");
            return null;
        }
    }

    public static void signDoipMessage(DoipMessage msg) throws Exception {
        if(msg.credential != null){
            logger.debug("message has been signed, return.");
            return;
        }
        msg.header.setIsCertified(true);
        MessageCredential credential = new MessageCredential(GlobalConfigurations.userID);
        PacketMessageCodec codec = new PacketMessageCodecImpl();
        credential.setSignature(CertUtils.Sign(codec.MessageToBytes(msg), GlobalCertifications.getGlobalJWK()).getBytes());
        msg.credential = credential;
        msg.header.setIsCertified(true);
    }

    public static boolean verifyDoipMessage(DoipMessage msg) throws Exception{
        if(msg.credential == null || msg.credential.getSigner()==null){
            logger.debug("null message credential");
            return false;
        }
        try {
            UserStateInfo recipientInfo = new UserStateInfo(GlobalIrpClient.getGlobalClient().resolve(msg.credential.getSigner()));
            logger.debug("sender pk: " + recipientInfo.getPubkey());
            JWK sender = JWK.parse(recipientInfo.getPubkey());
            DoipMessage msgWithoutCredential = new DoipMessage("","");
            msgWithoutCredential.header = msg.header;
            msgWithoutCredential.body = msg.body;
            msgWithoutCredential.credential = null;
            PacketMessageCodec codec = new PacketMessageCodecImpl();
            return CertUtils.verify(codec.MessageToBytes(msgWithoutCredential),new String(msg.credential.getSignature()),sender);
        } catch (IrpClientException ie) {
            logger.warn("resolution recipient's pk failed, will not do encryption");
            return false;
        }
    }
}
